package bb.lanxing.manager;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

import bb.lanxing.util.Log;

public class SystemSensorManager {
    private static final String TAG = "SystemSensorManager";
    private static volatile SystemSensorManager instance;
    private Sensor accSensor;
    private Sensor magneticSensor;
    private Sensor pressureSensor;
    private SensorManager sensorManager;
    private float altitudeFromPressure = 0.0f;
    private boolean isPressureOpened = false;
    private final float SMOOTH_FACTOR = 0.1f;
    private final float SMOOTH_FACTOR_INV = 0.9f;
    private float[] mAccelVals = {0.0f, 0.0f, 9.8f};
    private float[] mMagVals = {0.5f, 0.0f, 0.0f};
    private float mRotation = 0.0f;

    private SensorEventListener sensorEventListener = new SensorEventListener() {
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }

        @Override
        public void onSensorChanged(SensorEvent event) {
            int type = event.sensor.getType();
//            Log.d(TAG, "onSensorChanged...type=" + type);
            if (type == Sensor.TYPE_ACCELEROMETER) {
                smooth(event.values, mAccelVals, mAccelVals);
                calculateOrientation();
            } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
                smooth(event.values, mMagVals, mMagVals);
            } else if (type == Sensor.TYPE_PRESSURE) {
                float vPressure = event.values[0];
                altitudeFromPressure = SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, vPressure);
//                double HypsometricPressure = Hypsometric(vPressure/10.0f, 10.0f);
//                double BarometricPressure = Barometric(vPressure/10.0f);
//                Log.d(TAG, "onSensorChanged...vPressure=" + vPressure
//                        + ", altitudeFromPressure=" + altitudeFromPressure
//                        + ", HypsometricPressure=" + HypsometricPressure + ", BarometricPressure=" + BarometricPressure);

            }
        }
    };

    private SystemSensorManager() {
    }

    public static SystemSensorManager getInstance() {
        if (instance == null) {
            synchronized (SystemSensorManager.class) {
                if (instance == null) {
                    instance = new SystemSensorManager();
                }
            }
        }
        return instance;
    }

    public static void terminate() {
        if (instance != null) {
            instance.release();
            instance = null;
        }
    }

    public void init(Context context) {
        SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        this.sensorManager = sensorManager;
        this.accSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        this.magneticSensor = this.sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        this.pressureSensor = this.sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
    }

    private void release() {
        this.sensorManager = null;
        this.accSensor = null;
        this.magneticSensor = null;
        this.pressureSensor = null;
    }

    public void startOrientationSensor() {
        Sensor sensor;
        SensorManager sensorManager = this.sensorManager;
        if (sensorManager == null || (sensor = this.accSensor) == null || this.magneticSensor == null) {
            return;
        }
        sensorManager.registerListener(this.sensorEventListener, sensor, SensorManager.SENSOR_DELAY_UI);
        this.sensorManager.registerListener(this.sensorEventListener, this.magneticSensor, SensorManager.SENSOR_DELAY_UI);
    }

    public void stopOrientationSensor() {
        Sensor sensor;
        SensorEventListener sensorEventListener;
        SensorManager sensorManager = this.sensorManager;
        if (sensorManager == null || (sensor = this.accSensor) == null
                || this.magneticSensor == null || (sensorEventListener = this.sensorEventListener) == null) {
            return;
        }
        sensorManager.unregisterListener(sensorEventListener, sensor);
        this.sensorManager.unregisterListener(this.sensorEventListener, this.magneticSensor);
    }

    public void startPressureSensor() {
        SensorManager sensorManager;
        if (this.isPressureOpened || (sensorManager = this.sensorManager) == null) {
            return;
        }
        sensorManager.registerListener(this.sensorEventListener, this.pressureSensor, SensorManager.SENSOR_DELAY_NORMAL);
        this.isPressureOpened = true;
    }

    public void stopPressureSensor() {
        SensorManager sensorManager;
        Sensor sensor;
        SensorEventListener sensorEventListener;
        if (!this.isPressureOpened || (sensorManager = this.sensorManager) == null
                || (sensor = this.pressureSensor) == null || (sensorEventListener = this.sensorEventListener) == null) {
            return;
        }
        sensorManager.unregisterListener(sensorEventListener, sensor);
        this.isPressureOpened = false;
    }

    public boolean isPressureWork() {
        return this.pressureSensor != null;
    }

    public boolean hasPressureSensor(Context context) {
        SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        Sensor pressureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
        Log.d(TAG, "hasPressureSensor " + ((pressureSensor != null) ? "TRUE" : "FALSE"));
        return pressureSensor != null;
    }

    public void smooth(float[] inv, float[] prevv, float[] outv) {
        outv[0] = (inv[0] * SMOOTH_FACTOR) + (prevv[0] * SMOOTH_FACTOR_INV);
        outv[1] = (inv[1] * SMOOTH_FACTOR) + (prevv[1] * SMOOTH_FACTOR_INV);
        outv[2] = (inv[2] * SMOOTH_FACTOR) + (prevv[2] * SMOOTH_FACTOR_INV);
    }

    public void calculateOrientation() {
        float[] fArr = new float[3];
        float[] fArr2 = new float[9];
        SensorManager.getRotationMatrix(fArr2, null, this.mAccelVals, this.mMagVals);
        SensorManager.getOrientation(fArr2, fArr);
        this.mRotation = (float) Math.toDegrees(fArr[0]);
    }

    public float getRotation() {
        return this.mRotation;
    }

    public float getAltitudeFromPressure() {
        return this.altitudeFromPressure;
    }

    public double Barometric(float CurrentPressure)
    {
        return 44330 * (1 - Math.pow(CurrentPressure / 101.325, 1 / 5.255));
    }

    public double Hypsometric(float CurrentPressure, float CurrentTemperature)
    {
        return (Math.pow(101.325 / CurrentPressure, 1 / 5.257) - 1) * (CurrentTemperature + 273.15) / 0.0065;
    }
}